package org.game.minesweeper.support;

import javafx.event.EventType;
import javafx.geometry.Pos;
import javafx.scene.control.Alert;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import org.game.cell.CellFactory;
import org.game.cell.config.Cell;
import org.game.cell.support.DefaultCellFactory;
import org.game.constant.APIConstant;
import org.game.support.TopStatusBarController;
import org.game.util.MapUtil;
import org.game.util.RandomUtil;

import java.util.HashMap;
import java.util.Map;

public abstract class MinesweeperMap extends TopStatusBarController {
    protected GridPane minesweeperMap;

    protected GridPane lastMap;

    protected CellFactory cellFactory = new DefaultCellFactory();

    protected int[][] direction = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};

    /**
     * 记录地图信息
     */
    protected Cell[][] cells;

    /**
     * 记录雷信息
     */
    protected Cell[] mines;

    protected void initMinesweeperMap() {
        lastMap = minesweeperMap;
        minesweeperMap = new GridPane();
        minesweeperMap.setAlignment(Pos.CENTER);
        int[][] map = new int[(int) APIConstant.CONFIG.get("width")][(int) APIConstant.CONFIG.get("height")];
        cells = cellFactory.getCellMap((int) APIConstant.CONFIG.get("width"), (int) APIConstant.CONFIG.get("height"));

        generateMine(map);
        generateCell(map);
    }

    protected void generateMine(int[][] map) {
        // 计算地图大小
        int size = (int) APIConstant.CONFIG.get("width") * (int) APIConstant.CONFIG.get("height");
        // 计算生成雷的数量
        int minesNumber = size / 10;
        // 记录雷的位置以免雷生成在同一个位置上
        Map<Integer, Integer> minesPos = new HashMap<>();

        mines = new Cell[minesNumber];

        for (int i = 0; i < minesNumber; i++) {
            // 生成雷的位置
            int pos = RandomUtil.randomInt(size);

            if (minesPos.get(pos) == null) {
                int x = pos % (int) APIConstant.CONFIG.get("width");
                int y = pos / (int) APIConstant.CONFIG.get("height");

                map[x][y] = 9;

                for (int j = 0; j < direction.length; j++) {
                    generateNumber(map, x + direction[j][0], y + direction[j][1]);
                }

                // 记录雷的位置
                minesPos.put(pos, 1);
            } else {
                i--;
            }
        }
    }

    protected void generateNumber(int[][] map, int x, int y) {
        if (MapUtil.isOutOfBounds(x, y, cells.length, cells[1].length)) {
            return;
        }

        map[x][y]++;
    }

    protected void generateCell(int[][] map) {
        int k = 0;

        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map[i].length; j++) {
                Cell cell = cellFactory.getCell(map[i][j], i, j);

                if (cell.getMode() >= 9) {
                    mines[k++] = cell;
                }

                cell.addEventHandler(MouseEvent.ANY, mouseEvent -> {
                    checkGame();

                    EventType eventType = mouseEvent.getEventType();

                    String mouseEventType = mouseEvent.getButton().name();

                    if (eventType == MouseEvent.MOUSE_PRESSED && "PRIMARY".equals(mouseEventType)) {
                        passedOrReleasedEvent(cell, true);
                        return;
                    }

                    if (eventType == MouseEvent.MOUSE_RELEASED && "PRIMARY".equals(mouseEventType)) {
                        passedOrReleasedEvent(cell, false);
                        return;
                    }

                    // 设置左键事件逻辑
                    if ("PRIMARY".equals(mouseEventType)) {
                        leftClickEvent(cell);
                        return;
                    }

                    // 设置右键事件逻辑
                    if ("SECONDARY".equals(mouseEventType)) {
                        rightClickEvent(cell);
                        return;
                    }
                });
                cells[i][j] = cell;
                minesweeperMap.add(cell, i, j);
            }
        }
    }

    private void passedOrReleasedEvent(Cell cell, boolean mode) {
        int x = cell.getX();
        int y = cell.getY();

        for (int i = 0; i < direction.length; i++) {

            if (MapUtil.isOutOfBounds(x + direction[i][0], y + direction[i][1], cells.length, cells[1].length)) {
                continue;
            }

            cells[x + direction[i][0]][y + direction[i][1]].showPassedOrReleasedColor(mode);
        }
    }

    private void leftClickEvent(Cell cell) {
        if (cell.isFlag()) {
            // 被标记的格子无法点击
            return;
        }

        if (cell.getMode() >= 9) {
            // 触发雷
            reset.setImage(new Image("/image/cry.png"));
            isStop = true;
            lockCells(true);

            return;
        }

        if (cell.getMode() == 0) {
            // 需要将附近所有的 0 自动显示出来
            // 算法设计思路是通过 对该 0 点的上下左右进行递归计算 直到被计算点不为 0 时结束
            showBlank(cell.getX(), cell.getY());
        }

        cell.showMode();
    }

    private void lockCells(boolean isDead) {
        for (int i = 0; i < cells.length; i++) {
            for (int j = 0; j < cells[i].length; j++) {
                cells[i][j].setDisable(true);
                if (cells[i][j].getMode() >= 9 && isDead) {
                    cells[i][j].showMinesColor();
                }

                if (!cells[i][j].isShow() && !isDead) {
                    cells[i][j].showClickColor();
                }
            }
        }
    }

    private void showBlank(int x, int y) {
        if (MapUtil.isOutOfBounds(x, y, cells.length, cells[1].length)) {
            return;
        }

        Cell cell = cells[x][y];

        if (cell.isShow()) {
            return;
        }

        if (cell.getMode() != 0) {
            // 该点不是 0 返回
            // 同时显示该点数值 如果其不是雷的话
            if (cell.getMode() < 9) {
                cell.showMode();
            }
            return;
        }

        cell.showMode();

        for (int j = 0; j < direction.length; j++) {
            showBlank(x + direction[j][0], y + direction[j][1]);
        }
    }

    private void rightClickEvent(Cell cell) {
        cell.setFlag(!cell.isFlag());
        if (cell.isFlag()) {
            cell.showFlagColor();
        } else {
            cell.showDefaultColor();
        }
    }

    private void checkGame() {
        for (int i = 0; i < mines.length; i++) {
            if (!mines[i].isFlag()) {
                return;
            }
        }

        lockCells(false);

        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("你赢了");
        alert.setHeaderText("");
        alert.setContentText("你赢了");
        alert.showAndWait();

        APIConstant.TIME_SERVICE.shutdown();
    }
}
